﻿using System;
using System.Collections.Generic;
using System.Data.EntityClient;
using System.Linq;
using System.ServiceModel;
using System.Text;
//using ggHD.Data.Models;
using Autofac;
using ggHD.DAL.Modules;
using ggHD.DAL.Repositories;
using ggHD.Domain.BizObj;
using ggHD.Domain.Repisitories;
using ggHD.Mail;
using LinqToDB;
using NLog;
using OpenPop.Mime;
using OpenPop.Mime.Header;


namespace ggHD.Data
{
    public class MailService : IMailService
    {

        private Logger _logger = LogManager.GetCurrentClassLogger();
        private static IContainer _container;
        private Lazy<IRawMailRepository> _rawMailRepository = new Lazy<IRawMailRepository>(() => _container.Resolve<IRawMailRepository>());
        private Lazy<IExternalInitiatorRepository> _extInitiatorRepository = new Lazy<IExternalInitiatorRepository>(() => _container.Resolve<IExternalInitiatorRepository>());
        private IRawMailRepository RawMailRepository
        {
            get
            {
                return _rawMailRepository.Value;
            }

        }
        private IExternalInitiatorRepository ExternalInitiatorRepository
        {
            get
            {
                return _extInitiatorRepository.Value;
            }
        }

        public MailService()
        {

            InitializeModules();

            // var str = (new ggHDDB().ConnectionString);
            // _logWriter = new DbLogWriter(str);
        }

        private void InitializeModules()
        {
            var b = new ContainerBuilder();
            b.RegisterModule(new DalModule());
            _container = b.Build();

        }

        /// <summary>
        /// Загрузка писем из указанного источника
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public int LoadRawMails(DateTime date)
        {
            date = date.Date;
            var date2 = date.AddDays(1);

            int res = 0;

            try
            {
                IEnumerable<MailAccount> accounts = GetMailAccounts();

                if (accounts.Count() == 0)
                {
                    throw new MailServiceLoadException("Не указаны аккаунты в настройках для загрузки писем");
                }

                var loadedUids = RawMailRepository.Select(m => m.DateSent.Value.Date == date).Select(m => m.MsgUid).ToArray();

                foreach (var account in accounts)
                    using (var loader = new MailLoader(account.Host, account.Port, account.Ssl, account.User, account.Password, loadedUids))
                    {
                        var messages = loader.LoadMessages(date, null);

                        if (!messages.Any())
                            throw new MailServiceLoadException(string.Format("Нет сообщений для аккаунта {0}:{1}", account.Host, account.User));

                        using (var db = _container.Resolve<IUnitOfWork>())
                        {
                            messages.ToList().ForEach(m =>
                            {
                                SaveMail(m, db);
                                res++;
                            });
                        }
                    }
            }
            catch (MailServiceLoadException ex)
            {
                _logger.ErrorException("Ошибка при загрузке писем", ex);

            }
            catch (Exception ex)
            {
                _logger.ErrorException("Непредвиденное исключение при загрузке писем", ex);
            }

            return res;

        }

        public IEnumerable<RawMail> GetMailHeaders(DateTime dateFrom, DateTime dateTo)
        {
            dateFrom = dateFrom.Date;
            dateTo = dateTo.Date;
            var i = 0;
            var res = RawMailRepository.Select(m => (m.DateSent.Value.Date >= dateFrom) && (m.DateSent.Value.Date <= dateTo)).Take(2).ToArray();
            return res;
        }

        private void SaveMail(KeyValuePair<string, Message> msg, IUnitOfWork dbContext)
        {
            if (msg.Value == null && dbContext == null)
                throw new MailServiceLoadException("Отсутствуе сообщение или контекст БД для сохранения письма");

            var msgHdr = msg.Value.Headers;

            try
            {
                dbContext.BeginTrans();
                {
                    ExternalInitiatorRepository.Insert(new ExternalInitiator()
                    {
                        FromAddress = msgHdr.From.Address,
                        FromDisplayText = msgHdr.From.DisplayName
                    }, true);

                    //_logger.Info(dbContext.LastQuery);

                    RawMailRepository.Insert(RawMail.CreateFromMessage(msg.Value, msg.Key));

                    //_logger.Info(dbContext.LastQuery);
                }
                dbContext.Commit();
            }
            catch (Exception ex)
            {
                dbContext.Rollback();
                throw;
            }

        }

        private IEnumerable<MailAccount> GetMailAccounts()
        {
            return new[] { new MailAccount("pop.tradeportal.ru", 110, false, "sokolov_sa@tradeportal.ru", "serges100") };
        }
    }

    internal class MailAccount
    {
        public readonly string Host;
        public readonly int Port;
        public readonly bool Ssl;
        public readonly string User;
        public readonly string Password;

        public MailAccount(string host, int port, bool ssl, string user, string pass)
        {
            Host = host;
            Port = port;
            Ssl = ssl;
            User = user;
            Password = pass;
        }
    }
}
